#define  WIN32_LEAN_AND_MEAN
#include "WinContexts.h" // includes windows.h
#include <gl\gl.h>
#include <gl\glu.h>
#include "VisualElement.h"
#include "matrix.h"
#include "OpenGLFonts.h"

#include "data.h"  // data and some program procesdures and variables

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )
{

     if( !SetAndRegisterWndClass( &WndClass , "OpenGL" , WindowProcedure ) )
     {
       MessageBox( NULL , "Cannot Register Window Class." , "Error !" , MB_OK );
       return 0;
     }


     WindowID = CreateWindowEx( WS_EX_CLIENTEDGE , "OpenGL" , "Kinematics" , 
                                WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_SYSMENU | WS_SIZEBOX ,
                                50 , 50 , 320 , 320 , NULL , NULL , hInstance , NULL );

       if( WindowID == NULL )
       {
         MessageBox( NULL , "Cannot Create Window." , "Error !" , MB_OK|MB_ICONERROR );
         return 0;
       }

       renCtx.initRendCtx( WindowID );
       renCtx.MakeCurrent( 1 );
      
       
       if( renCtx.good() )
       {

                  InitOpenGL( Main_Window );
                  ShowWindow( WindowID , SW_SHOW );
                  
                  hMenu = CreateMenu();
                  
                  MainPullDown = CreatePopupMenu();
                  Win1_Menu    = CreatePopupMenu();
                  Win2_Menu    = CreatePopupMenu();
                  Win3_Menu    = CreatePopupMenu();
                  Application  = CreatePopupMenu();
                  Programming  = CreatePopupMenu();
                  Online       = CreatePopupMenu();
                  Run          = CreatePopupMenu();
                  ASpeed       = CreatePopupMenu();
                  BSpeed       = CreatePopupMenu();
                  GSpeed       = CreatePopupMenu();
                  Alpha        = CreatePopupMenu();
                  Rotation     = CreatePopupMenu();
                  Settings     = CreatePopupMenu();
                  
                  
                  
                  InsertMenu( Application , 0xFFFFFFFF , MF_BYPOSITION|MF_STRING , ABOUT , "&About ..." );
                  InsertMenu( Application , 0xFFFFFFFF , MF_BYPOSITION|MF_STRING , CLOSE_APPLICATION , "&Close" );

                  InsertMenu( Win1_Menu , 0xFFFFFFFF , MF_BYPOSITION|MF_STRING , WIN1_SHOW , "&Show" );
                  InsertMenu( Win1_Menu , 0xFFFFFFFF , MF_BYPOSITION|MF_STRING , WIN1_HIDE , "&Hide" );
                  
                  InsertMenu( Win2_Menu , 0xFFFFFFFF , MF_BYPOSITION|MF_STRING , WIN2_SHOW , "&Show" );
                  InsertMenu( Win2_Menu , 0xFFFFFFFF , MF_BYPOSITION|MF_STRING , WIN2_HIDE , "&Hide" );
                  
                  InsertMenu( Win3_Menu , 0xFFFFFFFF , MF_BYPOSITION|MF_STRING , WIN3_SHOW , "&Show" );
                  InsertMenu( Win3_Menu , 0xFFFFFFFF , MF_BYPOSITION|MF_STRING , WIN3_HIDE , "&Hide" );
                  
                  InsertMenu( MainPullDown , 0xFFFFFFFF , MF_BYPOSITION|MF_STRING|MF_POPUP , (UINT)Win1_Menu , "&Parametres" );
                  InsertMenu( MainPullDown , 0xFFFFFFFF , MF_BYPOSITION|MF_STRING|MF_POPUP , (UINT)Win2_Menu , "&View from another camera" );
                  InsertMenu( MainPullDown , 0xFFFFFFFF , MF_BYPOSITION|MF_STRING|MF_POPUP , (UINT)Win3_Menu , "&View from mobile camera" );

                  InsertMenu( Online , 0xFFFFFFFF , MF_BYPOSITION|MF_STRING , ONLINE_PROGRAMMING_START , "&Start" );
                  InsertMenu( Online , 0xFFFFFFFF , MF_BYPOSITION|MF_STRING|MF_GRAYED , ONLINE_PROGRAMMING_STOP ,  "S&top" );
                  InsertMenu( Online , 0xFFFFFFFF , MF_BYPOSITION|MF_STRING|MF_GRAYED , ONLINE_PROGRAMMING_RESET , "&Reset" );
                  InsertMenu( Online , 0xFFFFFFFF , MF_BYPOSITION|MF_STRING|MF_SEPARATOR , 0 , "Separator" );
                  InsertMenu( Online , 0xFFFFFFFF , MF_BYPOSITION|MF_STRING , ONLINE_PROGRAMMING_INFO , "&Info" );
                  
                  InsertMenu( Programming , 0xFFFFFFFF , MF_BYPOSITION|MF_STRING|MF_POPUP , (UINT)Online , "&Online" );
                  InsertMenu( Programming , 0xFFFFFFFF , MF_BYPOSITION|MF_STRING|MF_GRAYED , 0 , "&Offline" );
                  
                  InsertMenu( Run , 0xFFFFFFFF , MF_BYPOSITION|MF_STRING|MF_GRAYED , ONLINE_PROGRAMMING_RUN_FORWARD , "Run &forward" );
                  InsertMenu( Run , 0xFFFFFFFF , MF_BYPOSITION|MF_STRING|MF_GRAYED , ONLINE_PROGRAMMING_RUN_BACKWARD , "Run &backward" );
                  
                  
                  InsertMenu( ASpeed , 0xFFFFFFFF , MF_BYPOSITION|MF_STRING|MF_DISABLED , 0 , "Degrees per keystroke" );
                  InsertMenu( ASpeed , 0xFFFFFFFF , MF_BYPOSITION|MF_SEPARATOR , 0 , "Separator" );
                  InsertMenu( ASpeed , 0xFFFFFFFF , MF_BYPOSITION|MF_STRING , ALPHA_SPEED_1_5 , "  &1.5  " );
                  InsertMenu( ASpeed , 0xFFFFFFFF , MF_BYPOSITION|MF_STRING , ALPHA_SPEED_2_5 , "  &2.5  " );
                  InsertMenu( ASpeed , 0xFFFFFFFF , MF_BYPOSITION|MF_STRING , ALPHA_SPEED_3_5 , "  &3.5  " );
                  InsertMenu( ASpeed , 0xFFFFFFFF , MF_BYPOSITION|MF_STRING , ALPHA_SPEED_4_5 , "  &4.5  " );
                  InsertMenu( ASpeed , 0xFFFFFFFF , MF_BYPOSITION|MF_STRING , ALPHA_SPEED_5_5 , "  &5.5  " );
                  
                  InsertMenu( BSpeed , 0xFFFFFFFF , MF_BYPOSITION|MF_STRING|MF_DISABLED , 0 , "Degrees per keystroke" );
                  InsertMenu( BSpeed , 0xFFFFFFFF , MF_BYPOSITION|MF_SEPARATOR , 0 , "Separator" );
                  InsertMenu( BSpeed , 0xFFFFFFFF , MF_BYPOSITION|MF_STRING , BETA_SPEED_1_5 , "  &1.5  " );
                  InsertMenu( BSpeed , 0xFFFFFFFF , MF_BYPOSITION|MF_STRING , BETA_SPEED_2_5 , "  &2.5  " );
                  InsertMenu( BSpeed , 0xFFFFFFFF , MF_BYPOSITION|MF_STRING , BETA_SPEED_3_5 , "  &3.5  " );
                  InsertMenu( BSpeed , 0xFFFFFFFF , MF_BYPOSITION|MF_STRING , BETA_SPEED_4_5 , "  &4.5  " );
                  InsertMenu( BSpeed , 0xFFFFFFFF , MF_BYPOSITION|MF_STRING , BETA_SPEED_5_5 , "  &5.5  " );

                  InsertMenu( GSpeed , 0xFFFFFFFF , MF_BYPOSITION|MF_STRING|MF_DISABLED , 0 , "Degrees per keystroke" );
                  InsertMenu( GSpeed , 0xFFFFFFFF , MF_BYPOSITION|MF_SEPARATOR , 0 , "Separator" );
                  InsertMenu( GSpeed , 0xFFFFFFFF , MF_BYPOSITION|MF_STRING , GAMMA_SPEED_1_5 , "  &1.5  " );
                  InsertMenu( GSpeed , 0xFFFFFFFF , MF_BYPOSITION|MF_STRING , GAMMA_SPEED_2_5 , "  &2.5  " );
                  InsertMenu( GSpeed , 0xFFFFFFFF , MF_BYPOSITION|MF_STRING , GAMMA_SPEED_3_5 , "  &3.5  " );
                  InsertMenu( GSpeed , 0xFFFFFFFF , MF_BYPOSITION|MF_STRING , GAMMA_SPEED_4_5 , "  &4.5  " );
                  InsertMenu( GSpeed , 0xFFFFFFFF , MF_BYPOSITION|MF_STRING , GAMMA_SPEED_5_5 , "  &5.5  " );
                  
                  
                  InsertMenu( Rotation , 0xFFFFFFFF , MF_BYPOSITION|MF_STRING|MF_POPUP , (UINT)ASpeed , "&Alpha" );
                  InsertMenu( Rotation , 0xFFFFFFFF , MF_BYPOSITION|MF_STRING|MF_POPUP , (UINT)BSpeed , "&Beta" );
                  InsertMenu( Rotation , 0xFFFFFFFF , MF_BYPOSITION|MF_STRING|MF_POPUP , (UINT)GSpeed , "&Gamma" );
                  
                  InsertMenu( Settings , 0xFFFFFFFF , MF_BYPOSITION|MF_STRING|MF_POPUP , (UINT)Rotation , "&Rotation" );                  
                  
                  InsertMenu( hMenu , 0xFFFFFFFF , MF_BYPOSITION|MF_STRING|MF_POPUP , (UINT)Application , "&Application" );
                  InsertMenu( hMenu , 0xFFFFFFFF , MF_BYPOSITION|MF_STRING|MF_POPUP , (UINT)MainPullDown , "&Window" );
                  InsertMenu( hMenu , 0xFFFFFFFF , MF_BYPOSITION|MF_STRING|MF_POPUP , (UINT)Programming , "&Programming" );
                  InsertMenu( hMenu , 0xFFFFFFFF , MF_BYPOSITION|MF_STRING|MF_POPUP , (UINT)Run , "&Run" );
                  InsertMenu( hMenu , 0xFFFFFFFF , MF_BYPOSITION|MF_STRING|MF_POPUP , (UINT)Settings , "&Modify" );
                  
                  SetMenu( WindowID , hMenu ); 

                  Draw( Main_Window );
                  renCtx.SwpBuffers();
       }
       else
       {
                  MessageBox( NULL , "Cannot create rendering context !" , "Error" , MB_OK|MB_ICONERROR );
                  renCtx.deleteCtx();
                  DestroyWindow( WindowID );
                  return 0;
       }
       
      CreateThread( NULL , 0 , ThreadFunction_1 , (LPVOID)hInstance , 0 , &threadID_1 );
      CreateThread( NULL , 0 , ThreadFunction_2 , (LPVOID)hInstance , 0 , &threadID_2 );
      CreateThread( NULL , 0 , ThreadFunction_3 , (LPVOID)hInstance , 0 , &mv_cam_thread );
      CreateThread( NULL , 0 , ThreadFunction_4 , (LPVOID)hInstance , 0 , &about_thread );
      
// ------------------------------------------------------------------------------------------------------------------------

      while( !ShutDown )
      {
            if( UpArrowPressed || DownArrowPressed || LeftArrowPressed || RightArrowPressed || PageUpPressed || PageDownPressed )
            {
                  if( PeekMessage( &Message , NULL , 0 , 0 , PM_REMOVE ) )
                  {
                       if( Message.message == WM_QUIT )
                       {
                            ShutDown = 1;
                            continue;
                       }
                       TranslateMessage( &Message );
                       DispatchMessage( &Message );
                       
                       if( UpArrowPressed    && (Steering.alpha_change <= 0) )  Steering.alpha -= Alpha_Incr;
                       if( DownArrowPressed  && (Steering.alpha_change >= 0) )  Steering.alpha += Alpha_Incr;
                       if( LeftArrowPressed  && (Steering.beta_change <= 0)  )  Steering.beta  -= Beta_Incr;
                       if( RightArrowPressed && (Steering.beta_change >= 0)  )  Steering.beta  += Beta_Incr;
                       
                       if( PageUpPressed   ) Steering.gamma -= Gamma_Incr;
                       if( PageDownPressed ) Steering.gamma += Gamma_Incr;

                       Draw( Main_Window ); 
                       renCtx.SwpBuffers();
                       
                       if( OnlineProgramming && ( StepsRegistered < 1000 ) )
                       {
                            ProgramStorage[ ++StepsRegistered - 1 ] = Steering;
                       }
                       
                  }
            }
            else
            {
                  if( GetMessage( &Message , NULL , 0 , 0 ) > 0 )
                  {
                        TranslateMessage( &Message );
                        DispatchMessage( &Message );
                  }
                  else ShutDown = 1;
            }
      }
      
  return Message.wParam;
} // Matches WinMain